package com.globalwave.rule.engine;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;

import com.globalwave.rule.engine.operator.OperatorFactory;
import com.globalwave.rule.engine.operator.OperatorInf;
import com.globalwave.rule.entity.RuleLimit;

import static com.globalwave.rule.engine.operator.OperatorInf.*;


/**
 * 条件结点，每一个结点包括了条件值、条件的比较符、逻辑运算符等
 * <p/>
 * 子结点与你结点的逻辑关系关系是“与”关系，子结点集按集合的先后顺序作为运算顺序，
 * 因此设置子结点集的第一个结点的逻辑运算符为“与”，以作为父结点与子结点集的的一种逻辑运算关系。
 * 
 * @author 陈向荣
 * @version 1.0
 * 
 * Modification history:
 * {date} Modified by {who} & {why} & {what} is modified
 */
public class LimitNode implements Cloneable , Serializable{

    private static final long serialVersionUID = 1L;

    protected Log log = LogFactoryImpl.getLog(this.getClass()) ;

    private Long id ;    
    
    private short logic_operator ;

    private Factor leftFactor ;
    
    private short operator_ ;
    private int type_ ;

    private Factor rightFactor ;
    
	public LimitNode() {
		
	}
	public LimitNode(RuleLimit limit) {
	    this.id = limit.getId() ;	    
	    this.logic_operator = limit.getLogic_operator() ;

	    this.leftFactor = 
	    	new Factor(
	    			limit.getL_property(), 
	    			limit.getL_convertor(), 
	    			limit.getL_value(), 
	    			limit.getType_() ) ;
	    
	    
	    this.operator_ = limit.getOperator_() ;

	    this.rightFactor = 
	    	new Factor(
	    			limit.getR_property(), 
	    			limit.getR_convertor(), 
	    			limit.getR_value(), 
	    			limit.getType_() ) ;
	}
    
    
    private boolean caculate(Map<String, Object> vars) throws Exception {

    	if (this.id == -1) {
    		return true ;
    	}
        Object leftValue = leftFactor.getValue(vars) ;
        Object rigthValue = rightFactor.getValue(vars) ;

        
        OperatorInf oper = OperatorFactory.newOperator(operator_) ;

        if (oper == null) {
            throw new Exception("Can't Find Operator ") ;
        }
        
        return oper.calculate(leftValue, rigthValue) ;
    }
    
    private List<LimitNode> children = new ArrayList<LimitNode>() ;

    /**
     * 把指定结点加入本结点的子结点集
     * 
     * @param limitNode 一个条件结点
     */
    public void addChildren(LimitNode limitNode) {
        if (limitNode == null) {
            return ;
        }
        
        if (children.size() == 0) {
            limitNode.logic_operator = OPERATOR_CD_AND ; // 为了统一处理，作为第一个条件，本来不需要逻辑运算符
        }
        
        children.add(limitNode) ;
    }
    
    /**
     * 根据传入的因子参数值，计算本结点是否符合条件
     * 
     * @param vars 因子参数值
     * @return true:符合本结点条件及子条件，false:不符合本结点条件及子条件。
     * @throws Exception
     */
    public boolean evaluate(Map<String, Object> vars) throws Exception {
        
        if(vars == null) {
            return false ;
        }
        
        boolean result = this.caculate(vars) ;// 计算当前条件值      
        
        // 如果父子关系，看作并关系处理
        if (result) {
            for (LimitNode childNode : children) {
                if (OPERATOR_CD_OR == childNode.getLogic_operator()) {
                    if (result) {
                        return true ;
                    } else {
                        result = childNode.evaluate(vars) ;
                        continue ;
                    }
                } 
                
                result = result && childNode.evaluate(vars) ;
            }
        } else {
            return false ;
        }
        
        return result ;
    }
    
    
    // -- getter / setter
    

    /**
     * 克隆本结点，浅克隆，不克隆本结点的子结点
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        LimitNode newNode = (LimitNode) super.clone();
        try {
            BeanUtils.copyProperties(newNode, this) ;
        } catch (Exception e) {
            log.error(e.getMessage(), e) ;
        }
        return newNode ;
    }

	public Log getLog() {
		return log;
	}

	public void setLog(Log log) {
		this.log = log;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public short getLogic_operator() {
		return logic_operator;
	}

	public void setLogic_operator(short logic_operator) {
		this.logic_operator = logic_operator;
	}


	public short getOperator_() {
		return operator_;
	}

	public void setOperator_(short operator_) {
		this.operator_ = operator_;
	}

	public int getType_() {
		return type_;
	}

	public void setType_(int type_) {
		this.type_ = type_;
	}



	public List<LimitNode> getChildren() {
		return children;
	}

	public void setChildren(List<LimitNode> children) {
		this.children = children;
	} 
    
    
}
